<template>
<div class="parent">
    <div id="container">
    </div>
    <div id="controls">
    </div>
</div>
</template>

<script setup lang="ts">
import * as THREE from 'three';
import { onMounted } from 'vue'; 
import {GUI} from 'three/examples/jsm/libs/lil-gui.module.min.js';

onMounted(()=>{
    const scene = new THREE.Scene();
    const fov = 75;
	const aspect = 2; // the canvas default
	const near = 0.1;
	const far = 5;
	const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
	camera.position.z = 2;
    const renderer = new THREE.WebGLRenderer({antialias: true});
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.getElementById("container")?.appendChild(renderer.domElement);

	const boxWidth = 1;
	const boxHeight = 1;
	const boxDepth = 1;
	const geometry = new THREE.BoxGeometry( boxWidth, boxHeight, boxDepth );
    
	const cubes:THREE.Mesh[] = []; // just an array we can use to rotate the cubes
	const loader = new THREE.TextureLoader();

	const texture = loader.load( '/pngs/wall.jpg' );
	texture.colorSpace = THREE.SRGBColorSpace;
	const material = new THREE.MeshBasicMaterial( {
		map: texture,
	} );
    const cube = new THREE.Mesh( geometry, material );
	scene.add( cube );
	cubes.push( cube );

    class DegRadHelper {
        obj:any;
        prop:any;
        constructor(obj:any, prop:any) {
            this.obj = obj;
            this.prop = prop;
        }
		get value() {
            return THREE.MathUtils.radToDeg( this.obj[ this.prop ] );
        }
        set value( v ) {
            this.obj[ this.prop ] = THREE.MathUtils.degToRad( v );
        }
    }

    class StringToNumberHelper {
        obj:any;
        prop:any;
        constructor( obj:any, prop:any ) {
            this.obj = obj;
            this.prop = prop;
        }
        get value() {
            return this.obj[ this.prop ];
        }
        set value( v ) {
            this.obj[ this.prop ] = parseFloat( v );
        }
    }

	const wrapModes = {
		'ClampToEdgeWrapping': THREE.ClampToEdgeWrapping,
		'RepeatWrapping': THREE.RepeatWrapping,
		'MirroredRepeatWrapping': THREE.MirroredRepeatWrapping,
	};

    function updateTexture() {
        texture.needsUpdate = true;
    }

    //观察gui的使用方式
    const gui = new GUI({container: document.getElementById('controls')!!});
    gui.add( new StringToNumberHelper( texture, 'wrapS' ), 'value', wrapModes )
		.name( 'texture.wrapS' )
		.onChange( updateTexture );
	gui.add( new StringToNumberHelper( texture, 'wrapT' ), 'value', wrapModes )
		.name( 'texture.wrapT' )
		.onChange( updateTexture );
	gui.add( texture.repeat, 'x', 0, 5, .01 ).name( 'texture.repeat.x' );
	gui.add( texture.repeat, 'y', 0, 5, .01 ).name( 'texture.repeat.y' );
	gui.add( texture.offset, 'x', - 2, 2, .01 ).name( 'texture.offset.x' );
	gui.add( texture.offset, 'y', - 2, 2, .01 ).name( 'texture.offset.y' );
	gui.add( texture.center, 'x', - .5, 1.5, .01 ).name( 'texture.center.x' );
	gui.add( texture.center, 'y', - .5, 1.5, .01 ).name( 'texture.center.y' );
	gui.add( new DegRadHelper( texture, 'rotation' ), 'value', - 360, 360 )
		.name( 'texture.rotation' );

    const render = (time:number) => { 
        time *= 0.001;

        const canvas = renderer.domElement;
        const needResize = canvas.width !== canvas.clientWidth || canvas.height !== canvas.clientHeight;
        if (needResize){ //尺寸变化更新相机和渲染器
            renderer.setSize(canvas.clientWidth, canvas.clientHeight, false);
            camera.aspect = canvas.clientWidth / canvas.clientHeight;
            camera.updateProjectionMatrix();
        }

        cubes.forEach( ( cube, ndx ) => {
            const speed = .2 + ndx * .1;
            const rot = time * speed;
            cube.rotation.x = rot;
            cube.rotation.y = rot;
        } );

        renderer.render( scene, camera );
        requestAnimationFrame( render );
    };
    requestAnimationFrame( render );
})
</script>

<style scoped>
.parent {
    position: relative;
    width: 100%;
    height: 100%;
}
.parent > * {
    position: absolute;
}
#controls{
    right: 0;
}
</style>